package com.iqiyi.pps.epg.api.utils;

import com.iqiyi.kiwi.utils.Configuration;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.HttpHeaders;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

public class SsoUtil {
    public static Logger logger = LoggerFactory.getLogger(SsoUtil.class);

    public final static String LEGO_USERID_COOKIE_KEY = "L00001";   // cookie name
    private final static String COOKIE_ENCODE_KEY = Configuration.getString("sso.cookie.encode.key"); // MD5 key

    /**
     * 判断用户是否已登录调用此方法
     * 根据request获取sso的用户邮箱
     * 若返回null则说明用户未登录,须让用户先登录
     * @param httpHeaders
     * @return 用户邮箱
     */
    public static String getSsoUsername(HttpHeaders httpHeaders){
        // 1.获取用户cookie
        String cookie = null;
        Map<String, Cookie> cookies = getCookies(httpHeaders);
        if (!cookies.isEmpty()) {
            for (Map.Entry<String, Cookie> item : cookies.entrySet()) {
                if (item.getKey().equalsIgnoreCase(LEGO_USERID_COOKIE_KEY)) {
                    cookie = item.getValue().getValue();
                    break;
                }
            }
        }
        logger.info("[SsoUtil][getSsoUsername][cookie={}]", cookie);
        // 2.校验
        if (cookie != null) {
            return authenticateCookie(cookie);
        }
        return null;
    }

    public static String getLegoLoginCookie(HttpHeaders httpHeaders){
        String cookie = null;
        Map<String, Cookie> cookies = getCookies(httpHeaders);
        if (!cookies.isEmpty()) {
            for (Map.Entry<String, Cookie> item : cookies.entrySet()) {
                if (item.getKey().equalsIgnoreCase(LEGO_USERID_COOKIE_KEY)) {
                    cookie = item.getValue().getValue();
                    break;
                }
            }
        }
        return cookie;
    }

    /**
     * 验证cookie值是否有效
     * 有效则返回用户邮箱，无效则返回null
     * @param cookie
     * @return
     */
    private static String authenticateCookie(String cookie) {
        String username;
        try {
            // 1.Base64解密 cookie值
            byte[] cookieByte = base64Decode(cookie);
            String decodeCookie = new String(cookieByte);
            logger.info("decodeCookie:"+decodeCookie);

            // 2.解析解压完的值,并校验
            String[] values = decodeCookie.split(":", 3);
            // 判断数组大小
            if (values.length != 3) {
                logger.info("values:length= 3 ");
                return null;
            }
            // 判断有效期
            Long validTime = Long.parseLong(values[1]);
            if (validTime < System.currentTimeMillis()) {
                logger.info("validTime <  System.currentTimeMillis()");
                return null;
            }
            username = values[0];
            // 判断MD5是否一致
            String encodeMd5 = values[2]; // 获取cookie中的MD5加密值
            String oriMd5 = username + validTime + COOKIE_ENCODE_KEY; // MD5原值
            String calMd5 = MD5(oriMd5, "utf-8"); // 计算MD5加密
            if (!encodeMd5.equals(calMd5)) {
                logger.info("!encodeMd5.equals(calMd5) ,calMd5: {}",calMd5);
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Exception e ",e);
            return null;
        }
        return username;
    }

    private static Map<String, Cookie> getCookies(HttpHeaders httpHeaders) {
        Map<String, Cookie> cookies = httpHeaders.getCookies();
        logger.info("[SsoUtil][getCookies][cookies=]", cookies);
        return cookies;
    }

    /**
     * 生成cookie值
     * @param username    用户名
     * @param validTime   cookie有效期
     * @return
     */
    private static String genCookie(String username, long validTime) {
        // 1.从当前时间算有效期
        validTime = System.currentTimeMillis() + validTime;
        // 2.计算cookie值
        String oriMd5 = username + validTime + COOKIE_ENCODE_KEY; // MD5原值
        String calMd5 = MD5(oriMd5, "utf-8"); // MD5加密
        String value = username + ":" + validTime + ":" + calMd5; // 构建Base64原串
        String cookie = base64Encode(value.getBytes()); // Base64加密

        return cookie;
    }

    /**
     * Base64编码.
     * @param input 需要编码的字节数组
     * @return 编码后的字符串
     */
    private static String base64Encode(byte[] input) {
        return new String(Base64.encodeBase64(input));
    }

    /**
     * Base64解码.
     * @param input 需要解码的字符串
     * @return 转码后的字节数组
     */
    private static byte[] base64Decode(String input) {
        return Base64.decodeBase64(input);
    }

    private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6',
        '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * MD5加密, 默认UTF-8
     * @param text  需要加密的文本
     * @param charset  加密的编码格式
     * @return 加密串
     */
    private static String MD5(String text, String charset) {
        MessageDigest msgDigest;
        try {
            msgDigest = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalStateException("System doesn't support MD5 algorithm.");
        }
        try {
            msgDigest.update(text.getBytes(charset)); // 注意改接口是按照指定编码形式签名
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException("System doesn't support your  EncodingException.");
        }
        byte[] bytes = msgDigest.digest();
        String md5Str = new String(encodeHex(bytes));
        return md5Str;
    }

    private static char[] encodeHex(byte[] data) {
        int l = data.length;
        char[] out = new char[l << 1];
        // two characters form the hex value.
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
            out[j++] = DIGITS[0x0F & data[i]];
        }
        return out;
    }

    /**
     * 判断字符串是否是一个IP地址
     * @param addr 字符串
     * @return true:IP地址，false：非IP地址
     */
    private static boolean isIPAddr(String addr) {
        if (StringUtils.isEmpty(addr)) {
            return false;
        }
        String[] ips = StringUtils.split(addr, '.');
        if (ips.length != 4) {
            return false;
        }
        try {
            int ipa = Integer.parseInt(ips[0]);
            int ipb = Integer.parseInt(ips[1]);
            int ipc = Integer.parseInt(ips[2]);
            int ipd = Integer.parseInt(ips[3]);
            return ipa >= 0 && ipa <= 255 && ipb >= 0 && ipb <= 255 && ipc >= 0
                && ipc <= 255 && ipd >= 0 && ipd <= 255;
        } catch (Exception e) {}
        return false;
    }
}
